# encoding=utf-8
import os
import shutil
import json
import re
import binascii
import sys

#当前文件夹路径
current_path = os.getcwd()

#渠道的配置路径
channle_path = os.path.join( current_path, "channel" )

#默认进行处理的apk基础包
default_apk_name = "hlqx.apk"

#如果遇到要处理的apk基础包的名称是中文，则运行命令时可能出现问题
#因而使用一个中间文件进行处理
temp_unpack_apk_name = "temp_unpack.apk"

#使用到的jdk的路径
jdk_path = "";

#使用到的apktool的路径
apktool_path = os.path.join( current_path, "tools" )

#akp解压生成的中间文件的名称
apk_temp_dir = "temp"

#生成的中间的未签名的apk文件名称
apk_temp_name = "temp.apk"

#所用渠道通用的资源替换
comment_replace_res_config = "comment_replace_res"

#无签名游戏包输出文件夹
apk_no_sign_out_dir = "apk_no_sign"

#签名游戏包输出文件夹
apk_sign_out_dir = "apk_sign"

#所用渠道通用的文本替换
comment_replace_res_name = "config.json"
comment_replace_txt_dir = "comment_replace_txt"
comment_replace_txt_config = os.path.join( comment_replace_txt_dir, comment_replace_res_name )


#重新设置压缩忽略列表
def reset_do_not_compress_config():
    print ""
    print "#"*25
    print "reset do not compress config"
    yml_path = os.path.join( os.path.join( current_path, apk_temp_dir ), "apktool.yml")
    yml_file = open( yml_path, "r+" )
    yml_content = yml_file.readlines()

    start_index = yml_content.index("doNotCompress:\n")
    end_index = yml_content.index("isFrameworkApk: false\n")
    for i in range( 0, end_index - start_index -1 ):
        del yml_content[start_index+1]
    yml_content.insert(start_index+1, "- zip\n")
    yml_content.insert(start_index+1, "- bin\n")
    yml_content.insert(start_index+1, "- uwc\n")
    yml_content.insert(start_index+1, "- csb\n")
    yml_content.insert(start_index+1, "- arsc\n")
    yml_content.insert(start_index+1, "- xml\n")

    yml_file.seek(0)
    yml_file.truncate()
    yml_file.writelines( yml_content )
    yml_file.close()

    print "#"*25
    print ""

#解压一个apk包
def unpack_apk( apk_name ):
    print ""
    print "#"*25
    print "unpack apk:" + apk_name

    #尝试删除中间文件，避免上次解压apk包的影响
    if apk_temp_dir in os.listdir( current_path ):
        shutil.rmtree( apk_temp_dir, True )
    # java_exe_path = os.path.join( os.path.join( jdk_path, "bin" ), "java" )
    java_exe_path = "java";
    apktool_jar_path = os.path.join( apktool_path, "apktool.jar" )
    #print java_exe_path
    unpack_apk_command = java_exe_path + " -jar" + " " + apktool_jar_path + " d" + " " + os.path.join( current_path, apk_name )
    unpack_apk_command += " -o" + " " + apk_temp_dir
    #print unpack_apk_command
    os.system( unpack_apk_command )

    print "#"*25
    print ""

#打出一个apk包
#param apk_name:打出的apk包的名称
def pack_apk():
    print ""
    print "#"*25
    print "pack apk"

    # java_exe_path = os.path.join( os.path.join( jdk_path, "bin" ), "java" )
    java_exe_path = "java";
    apktool_jar_path = os.path.join( apktool_path, "apktool.jar" )
    pack_apk_command = java_exe_path + " -jar" + " " + apktool_jar_path + " b" + " " + apk_temp_dir
    pack_apk_command += " -o " + os.path.join( current_path, apk_temp_name )
    #print pack_apk_command
    os.system( pack_apk_command )

    print "#"*25
    print ""

#对一个包进行签名
#param
#apk_name:需要签名的apk包
#app_seed_name:使用到的签名文件
#app_seed_pass_world:签名文件的密码 [eclipse打包时第一次输入的密码]
#app_seed_list_name:签名的列表中使用到的对应的列表的名称 [eclipse打包时列表中选择的名称]
#app_seed_list_pass_world:列表的密码 [eclipse打包时第二次输入的密码]
def sign_apk( apk_name, app_seed_name, app_seed_pass_world, app_seed_list_name, app_seed_list_pass_world ):
    print ""
    print "#"*25
    print "sign apk:" + apk_name
    apk_out_path = os.path.join(current_path, apk_sign_out_dir)
    if not os.path.exists( apk_out_path ):
        os.mkdir( apk_out_path )

    # jarsigner_exe_path = os.path.join( os.path.join( jdk_path, "bin" ), "jarsigner" )
    jarsigner_exe_path = "jarsigner";
    sign_apk_command = jarsigner_exe_path + " -verbose -keystore " + os.path.join( current_path, app_seed_name )
    sign_apk_command += " -digestalg SHA1 -sigalg MD5withRSA"
    sign_apk_command += " -storepass " + app_seed_pass_world + " -keypass " + app_seed_list_pass_world
    sign_apk_command += " -signedjar " + os.path.join(apk_out_path, apk_name) + " " + os.path.join(current_path, apk_temp_name) + " " + app_seed_list_name
    #print sign_apk_command
    os.system( sign_apk_command )

    #签名完成后删除掉中间文件
    if os.path.exists( os.path.join( current_path, apk_temp_name ) ):
        os.remove( os.path.join( current_path, apk_temp_name ) )
    print "#"*25
    print ""

#把输入文件拷贝到输出文件，并对文件进行重命名
def copy_2_path_and_rename( from_path, to_path, to_name ):
    print ""
    print "#"*25
    print "copy from:" + from_path + " to:" + to_path + " rename:" + to_name
    if not os.path.exists( to_path ):
        os.mkdir( to_path )

    shutil.copy( from_path, os.path.join(to_path, to_name) )
    print "#"*25
    print ""

#查找所有需要的channle列表
def get_all_channle_package_list():
    print ""
    print "#"*25
    print "get all channle package list"

    rtn = []
    for signal_channle in os.listdir( channle_path ):
        #print os.path.join( current_path, signal_channle)
        #print os.path.isfile( os.path.join( current_path, signal_channle) )
        #???这里有一个不明白的错误，为什么最后返回的是False，明明就是一个文件夹的路径
        if True or os.path.isdir( os.path.join( current_path, signal_channle) ):
            rtn.append( os.path.join( channle_path, signal_channle) )

    print "#"*25
    print ""
    return rtn

#对文件加进行拷贝和替换
def copy_and_replace_res_file( src, dst ):
    print ""
    print "#"*25
    print "begin replace resource file:"
    print "from " + src.replace( current_path, "" ) + " to " + dst.replace( current_path, "" )
    #如果不存在此文件夹，那么就创建一个文件夹
    if not os.path.exists( dst ):
        os.mkdir( dst )

    for signal_replace in os.listdir( src ):
        current_src_path = os.path.join( src, signal_replace )
        current_dst_path = os.path.join( dst, signal_replace )
        if os.path.isfile( current_src_path ):
            shutil.copy( current_src_path, current_dst_path )
        elif os.path.isdir( current_src_path ):
            copy_and_replace_res_file( current_src_path, current_dst_path )
    print "#"*25
    print ""

#对文件加进行拷贝和替换
def copy_and_replace_code_file( src, dst ):
    print ""
    print "#"*25
    print "begin replace code file:"
    print "from " + src.replace( current_path, "" ) + " to " + dst.replace( current_path, "" )
    #如果不存在此文件夹，那么就创建一个文件夹
    if not os.path.exists( dst ):
        os.mkdir( dst )

    for signal_replace in os.listdir( src ):
        current_src_path = os.path.join( src, signal_replace )
        current_dst_path = os.path.join( dst, signal_replace )
        if os.path.isfile( current_src_path ):
            shutil.copy( current_src_path, current_dst_path )
        elif os.path.isdir( current_src_path ):
            copy_and_replace_res_file( current_src_path, current_dst_path )
    print "#"*25
    print ""

#对一个配置文件夹进行处理
def copy_and_replace_config_file( config_path ):
    print ""
    print "#"*25
    print "copy and replace config file"
    is_has_replace_config = False
    for signal_replace in os.listdir( config_path ):
        apk_temp_path = os.path.join( current_path, apk_temp_dir )
        apk_unknow_path = os.path.join( apk_temp_path, "unknown" )
        current_src_path = os.path.join( config_path, signal_replace )
        current_dst_path = os.path.join( apk_temp_path, signal_replace )
        if os.path.isdir( current_src_path ):
            if "smali"==signal_replace:
                copy_and_replace_code_file( current_src_path, current_dst_path )
            else:
                copy_and_replace_res_file( current_src_path, current_dst_path )
        elif os.path.isfile( current_src_path ):
            if comment_replace_res_name==signal_replace:
                #txt_replace_config( os.path.join( config_path, signal_replace) )
                is_has_replace_config = True
            elif signal_replace in os.listdir( apk_temp_path ):
                shutil.copy( current_src_path, current_dst_path )
            elif os.path.exists( apk_unknow_path ) and signal_replace in os.listdir( apk_unknow_path ):
                shutil.copy( current_src_path, os.path.join( apk_unknow_path, signal_replace) )
            else:
                shutil.copy( current_src_path, os.path.join( apk_temp_path, signal_replace ) )
    if is_has_replace_config:
        txt_replace_config( os.path.join( config_path, comment_replace_res_name) )
    print "#"*25
    print ""

#通用的AndroidManifest的内容替换
def txt_replace_config(config_path):
    print ""
    print "#"*25
    print "comment manifest replace:" + config_path

    config_file = file(config_path)
    config_json_format_content = json.load( config_file )
    config_file.close()
    for it in config_json_format_content:
        if not it.has_key( "file" ):
            continue

        #获取处理所需的信息
        deal_txt_file = it["file"].encode("utf-8")
        deal_replace_before = it["replace_befoe"].encode("utf-8")
        deal_replace_after = it["replace_after"].encode("utf-8")

        #执行文本的替换并进行保存
        deal_file_path = os.path.join( os.path.join(current_path, apk_temp_dir), deal_txt_file )
        deal_file = open( deal_file_path, "rb+" )
        deal_content = deal_file.read() #"".join( deal_file.readlines() )

        #处理掉因为"     />"和"/>"不匹配的问题
        re_replace = re.compile( "\" */>" )
        deal_replace_before = re_replace.sub( "\"/>", deal_replace_before )
        deal_content = re_replace.sub( "\"/>", deal_content )

        deal_content = deal_content.replace( deal_replace_before, deal_replace_after, 1 )
        deal_file.seek(0)
        deal_file.truncate()
        deal_file.write( deal_content )
        deal_file.close()
        #print deal_content

    print "#"*25
    print ""

#通过渠道的文件夹名称推测对应的apk文件名
def suppose_apk_name_by_channle_dir_name( name ):
    return os.path.splitext(default_apk_name)[0] + "_" + name +".apk"

#根据文件配置读取对应渠道的apk文件名
def get_apk_name_by_xml( xml_path ):
    xml_config_path = os.path.join( xml_path, comment_replace_res_name )
    #渠道配置文件不存在，则根绝配置文件所在文件夹，推测文件名
    if not os.path.exists( xml_config_path ):
        xml_dir_name = os.path.basename( xml_path )
        return suppose_apk_name_by_channle_dir_name( xml_dir_name )

    #拥有配置文件，则尝试通过配置文件读取文件名称
    apk_name = ""
    config_file = file( xml_config_path )
    config_json_format_content = json.load( config_file )
    config_file.close()
    for it in config_json_format_content:
        if not it.has_key( "name" ):
            continue
        apk_name = it["name"] + ".apk"
        break

    #如果配置文件中没有给与可使用的文件名称，则根绝配置文件所在文件夹，推测文件名
    if apk_name == "":
        xml_dir_name = os.path.basename( xml_path )
        return suppose_apk_name_by_channle_dir_name( xml_dir_name )

    return apk_name


#通过渠道的文件夹名称获取apk的基础包名称
def get_apk_base_name( name ):
    return default_apk_name

if __name__ == "__main__":
    if "JAVA_HOME" in os.environ:
        jdk_path = os.environ["JAVA_HOME"]
    else:
        print u"未定义JAVA_HOME环境变量";
        exit();
    #解决jdk_path中Program Files包含空格的问题
    jdk_path = jdk_path.replace('Program Files', '"Program Files"');
    print jdk_path;

    for signal_channle_path in get_all_channle_package_list():
        #获取到对应处理的apk包名
        channle_dir_name = os.path.basename( signal_channle_path )

        #限定进行打包的渠道
        if channle_dir_name=="nlg" or channle_dir_name=="fzs" or channle_dir_name=="jhhd" or channle_dir_name=="mzw" or channle_dir_name=="zxly":
            l=[]
        else:
            continue

        # 猜测成功打包后，生成的游戏包的名称
        suppose_apk_name = get_apk_name_by_xml( signal_channle_path )
        
        #根据最终猜测出的输出的游戏包的名称，尝试以此作为基础包进行处理
        try_2_deal_apk_name = suppose_apk_name
        #learn: utf-8和str的转换
        # for name in os.listdir( current_path ):
        #     if name != try_2_deal_apk_name.encode("gbk"):
        #         continue
        if not os.path.exists( os.path.join( current_path, try_2_deal_apk_name.encode("gbk") ) ):
            print "#"*25
            print ""
            print u"不存在特定的游戏基础包：" + try_2_deal_apk_name + \
                    u" 将使用默认基础包：" + default_apk_name + u" 进行游戏打包"
            print "#"*25
            print ""
            
            try_2_deal_apk_name = default_apk_name
            if not os.path.exists( os.path.join( current_path, try_2_deal_apk_name ) ):
                print "#"*25
                print ""
                print u"用默认基础包：" + try_2_deal_apk_name + u" 不存在无法进行游戏打包"
                print "#"*25
                print ""
                exit(0)

        #创建解压文件的中间文件，避免基础包含有中文
        temp_unpack_from_path = os.path.join( current_path, try_2_deal_apk_name.encode("gbk") )
        temp_unpack_2_path = os.path.join( current_path, temp_unpack_apk_name )
        copy_2_path_and_rename( temp_unpack_from_path, current_path, temp_unpack_apk_name )

        try_2_deal_apk_name = temp_unpack_apk_name

        #对需要处理的apk进行解压
        unpack_apk( try_2_deal_apk_name )

        #重新设置压缩忽略列表，使打包前后包体的大小一致
        reset_do_not_compress_config()

        #添加通用的替换文件
        if os.path.exists( os.path.join(current_path, comment_replace_res_config) ):
            copy_and_replace_config_file( os.path.join(current_path, comment_replace_res_config) )

        #处理渠道中需要进行替换的文件夹
        if os.path.exists( signal_channle_path ):
            copy_and_replace_config_file( signal_channle_path )

        #进行通用的文本替换，因为是打包前最后进行的替换因而优先于渠道中的替换功能
        if os.path.exists( os.path.join(current_path, comment_replace_txt_config) ):
            txt_replace_config( os.path.join(current_path, comment_replace_txt_config) )

        #尝试打包出一个apk文件
        pack_apk()

        #拷贝打出来的apk包，不进行签名，放置在路径下
        unsign_apk_from_path = os.path.join( current_path, apk_temp_name )
        unsign_apk_2_path = os.path.join( current_path, apk_no_sign_out_dir )
        copy_2_path_and_rename(unsign_apk_from_path, unsign_apk_2_path, u"无签名_".encode("gbk") + suppose_apk_name.encode("gbk"));

        #生成输出的apk文件的中间名称，避免suppose_apk_name中含有中文
        temp_out_apk_name = suppose_apk_name_by_channle_dir_name(channle_dir_name)
        #对新生成的apk文件进行签名
        sign_apk( temp_out_apk_name, "qec6.keystore", "appleseed", "android.keystore", "appleseed")

        #把最终的输出文件命名为预期的输出文件
        if temp_out_apk_name != suppose_apk_name:
            temp_path = os.path.join( os.path.join( current_path, apk_sign_out_dir ), temp_out_apk_name )
            final_path = os.path.join( os.path.join( current_path, apk_sign_out_dir ), u"有签名_".encode("gbk") + suppose_apk_name.encode("gbk") )
            shutil.copy2( temp_path, final_path )

        #进行中间文件的清理
        os.remove( os.path.join( current_path, temp_unpack_apk_name ) )

        if temp_out_apk_name != suppose_apk_name:
            temp_path = os.path.join( os.path.join( current_path, apk_sign_out_dir ), temp_out_apk_name )
            os.remove( temp_path )

        # if apk_temp_dir in os.listdir( current_path ):
        #     shutil.rmtree( apk_temp_dir, True )
